/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "u8g2.h"
#include "screen.h"
#include "keyboard.h"
#include "task.h"
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
Task_t SCREEN;                //定义任务结构体SCREEN

float dutyout = 0.5;          //输出pwm波占空比
float frecout = 1000.0f;      //输出pwm波频率
float dutyin;                 //捕获pwm波占空比
float frecin;                 //捕获pwm波频率
float degree = 2;             //移相角度
float frec_mul;               //倍频后pwm波频率
float duty_mul;               //倍频后pwm波占空比
int extern_clk_count = 1;     //倍频倍率
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/**
 * @brief 屏幕显示函数，先利用printf函数将浮点数存入字符串数组后
 *        利用u8g2库自带的DrawStr函数输出到屏幕
 */
void oled()
{
	u8g2_FirstPage(&CAST_OLED);
  char dto[40];
  char fro[40];
  char dti[40];
  char fri[40];
  char dgr[40];
  char ecc[40];
  sprintf(dto, "duty_o:%.0f", dutyout * 100);
  sprintf(fro, "frec_o:%.0f", frecout);
  sprintf(dti, "duty_i:%.0f", dutyin * 100);
  sprintf(fri, "frec_i:%.0f", frecin);
  sprintf(dgr, "degree:%.0f", degree);
  sprintf(ecc, "Multi:%d", extern_clk_count);
  u8g2_FirstPage(&CAST_OLED);
  do
  {
    u8g2_DrawStr(&CAST_OLED, 0, 10, dto);    //根据考试时具体的要求显示，大概率是移相或倍频二选一
    u8g2_DrawStr(&CAST_OLED, 0, 22, fro);    //所以需要自己选择显示移相角度还是倍频倍率
    u8g2_DrawStr(&CAST_OLED, 0, 34, dti);
    u8g2_DrawStr(&CAST_OLED, 0, 46, fri);
    //u8g2_DrawStr(&CAST_OLED, 0, 58, dgr);
    u8g2_DrawStr(&CAST_OLED, 0, 58, ecc);
  }while(u8g2_NextPage(&CAST_OLED));
}
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();
  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_TIM4_Init();
  MX_TIM5_Init();
  MX_TIM9_Init();
  MX_USART1_UART_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
  TaskInit(&SCREEN, &oled, 100, -1);                      //屏幕刷新任务初始化
  oledInit();                                             //屏幕初始化

  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);               //定时器1 CH1开启pwm波输出
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);               //定时器3 CH3开启pwm波输出
  HAL_TIM_PWM_Start(&htim9, TIM_CHANNEL_1);               //定时器9 CH1开启pwm波输出
  HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);             //定时器2 CH1开启输入捕获
	HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);             //定时器2 CH2开启输入捕获
  /* USER CODE END 2 */

  /* Infinite loop */

  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    dutyin=(float)htim2.Instance->CCR2 / (float)htim2.Instance->CCR1;                       //利用定时器2两个Channel的CCR计算捕获pwm波的占空比
		frecin = 84000000.0f / (float)htim2.Instance->CCR1;                                     //利用定时器2 CH1的CCR计算捕获pwm波的频率

    frec_mul = extern_clk_count * frecin;                                                   //倍频后pwm波频率 = 倍频倍率 * 捕获频率
    duty_mul = dutyin;                                                                      //倍频后pwm波占空比 = 捕获占空比
		
		htim9.Instance->ARR = 84000000.0f / ((float)(htim9.Instance->PSC + 1) * frecout) - 1;   //根据输出频率计算定时器9的ARR
		htim9.Instance->CCR1 = (htim9.Instance->ARR + 1) * dutyout;                             //根据定时器9的ARR和输出占空比计算定时器9的CCR

    htim3.Instance->ARR = 84000000.0f / ((float)(htim3.Instance->PSC + 1) * frec_mul) - 1;  //根据倍频后频率计算定时器3的ARR
    htim3.Instance->CCR3 = (htim3.Instance->ARR + 1) * duty_mul;                            //根据定时器3的ARR和倍频后占空比计算定时器3的CCR

		RunTask(&SCREEN);                                                                       //运行屏幕刷新任务
		keyboardscan();                                                                         //轮询按键情况
		
	  static uint32_t key0tick = 0;                   //SW1可以增大输出pwm波占空比，步进2%
		if(GetKeyVal(0))
		{
			if(HAL_GetTick() - key0tick > 50)
			{
				dutyout += 0.02;
			}
			key0tick = HAL_GetTick();
		}
		
	  static uint32_t key1tick = 0;                   //SW2可以减小输出pwm波占空比，步进2%
		if(GetKeyVal(1))
		{
			if(HAL_GetTick() - key1tick > 50)
			{
				dutyout -= 0.02;
			}
			key1tick = HAL_GetTick();
		}
		
	  static uint32_t key2tick = 0;                   //SW3可以增大输出pwm波频率，步进50Hz，上限9kHz
		if(GetKeyVal(2))
		{
			if(HAL_GetTick() - key2tick > 50)
			{
				frecout += 50.0f;
        if(frecout >= 9000.0f)
				{
			  	frecout = 100.0f;
				}
			}
			key2tick = HAL_GetTick();
		}
		
	  static uint32_t key3tick = 0;                   //SW4可以减小输出pwm波频率，步进50Hz，下限100Hz
		if(GetKeyVal(3))
		{
			if(HAL_GetTick() - key3tick > 50)
			{
				frecout -= 50.0f;
        if(frecout <= 100.0f)
				{
				  frecout = 100.0f;
				}
			}
			key3tick = HAL_GetTick();
		}
		
	  static uint32_t key4tick = 0;                   //SW5可以将输出波形相位左移，步进2度，上限720度
		if(GetKeyVal(4))
		{
			if(HAL_GetTick() - key4tick > 50)
			{
				degree += 2;
				if(degree >= 720)
				{
					degree = 0;
				}
			}
			key4tick = HAL_GetTick();
		}
		
	  static uint32_t key5tick = 0;                   //SW6可以将输出波形相位右移，步进2度，下限0度
		if(GetKeyVal(5))
		{
			if(HAL_GetTick() - key5tick > 50)
			{
				degree -= 2;
				if(degree <= 0)
				{
					degree = 0;
				}
			}
			key5tick = HAL_GetTick();
		}
		
	  static uint32_t key6tick = 0;                   //SW7可以将输出波形频率和占空比调整为与捕获pwm波一致
		if(GetKeyVal(6))
		{
			if(HAL_GetTick() - key6tick > 50)
			{
				frecout = frecin;
				dutyout = dutyin;
			}
			key6tick = HAL_GetTick();
		}

    static uint32_t key8tick = 0;                   //SW9可以让输出波形频率倍频+1，上限6倍频
		if(GetKeyVal(8))
		{
			if(HAL_GetTick() - key8tick > 50)
			{
        extern_clk_count++;
        if(extern_clk_count > 6)
				{
					extern_clk_count = 1;
				}
			}
			key8tick = HAL_GetTick();
		}

    static uint32_t key9tick = 0;                   //SW10可以让输出波形频率倍频-1，上限1倍频
		if(GetKeyVal(9))
		{
			if(HAL_GetTick() - key9tick > 50)
			{
        extern_clk_count--;
        if(extern_clk_count <= 1)
				{
					extern_clk_count = 1;
				}
			}
			key9tick = HAL_GetTick();
		}
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/**
  * @brief 定时器中断回调函数
  * @retval None
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef*htim)
{
	if(htim->Instance == htim4.Instance)
	{		
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
		HAL_TIM_Base_Stop(&htim4);
		htim4.Instance->CNT = 0;
	}
	if(htim->Instance == htim5.Instance)
	{
		HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
		HAL_TIM_Base_Stop(&htim5);
		htim5.Instance->CNT = 0;
	}
}

/**
  * @brief 输入捕获中断回调函数
  * @retval None
  */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if (htim->Instance == htim2.Instance)
	{
		if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0))
		{
			htim4.Instance->ARR = htim9.Instance->ARR * degree / 360;  //根据degree的值进行延时
			HAL_TIM_Base_Start_IT(&htim4);
		}
		if (!HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0))
		{
			htim5.Instance->ARR = htim9.Instance->ARR * degree / 360;
			HAL_TIM_Base_Start_IT(&htim5);
		}
    if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) 
    {
      TIM3->EGR |= 0x0001;   //使得倍频后的波形与输入波形对齐，防止波形漂移
    }
	}
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
